﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Bling.DSL;
using Bling.WPF;
using Bling.Core;

using Bling.Graphics;
using Bling.Util;

namespace Bling.Tutorial {
  public class Menus : Canvas, ICanStart {
    public static readonly DoubleBl TimeOut = 2500; // 2.5 seconds.
    public static readonly double Dur = 500; 
    public static readonly int Step = 100;
    public static readonly DoubleBl CatRadius = 100d;
    public static readonly DoubleBl SubCatRadius = 100d;

    public static readonly PointBl MinimizedYAH = new PointBl(20, 20);

    private readonly TimeoutManager<Menus> Timer;


    private static readonly GetProperty<Menus, int> SelectedCatProperty = "SelectedCat".NewProperty<Menus, int>(0);
    private IntBl SelectedCat { get { return SelectedCatProperty[this]; } set { SelectedCat.Bind = value; } }




    public Menus() {

      CanvasBl Self = this;
      Self.ClipToBounds = true;

      var Map = new CanvasBl(Self) {
        ZIndex = 0,
        Size = Self.Size,
        LeftTop = 0d,
        Background = Brushes.White,
      };
      BoolBl LockTime0 = false;
      var State = new LabelSliderBl(Self) {
        Minimum = 0,
        Maximum = 3d,
        Value = 0,
        LabelName = "State",
        LeftTop = new PointBl(0d, 0d),
        Visibility = true,
      };
      var RoundedState = State.Value.Round;
      Timer = new TimeoutManager<Menus>(this, TimeOut, Step, (Menus SelfA) => {
        DoubleBl Target = RoundedState;
        Target = (Target <= 1d).Condition(0d, 3d);
        State.Value.Animate().Duration(Dur).StopOnCompleted(true).To = Target;
      });
      State.Background = Timer.LockTime.Condition(Brushes.Red.Bl(), Brushes.Transparent.Bl());
      LockTime0 = !Map.IsMouseOver;
      var CurrentState = State.Value.AsFunc;
      var YAH = new EllipseBl(Self) {
        Stroke = { Thickness = 0 },
        ZIndex = 10, Fill = Brushes.Transparent,
        CenterPosition = Self.CenterSize + (State.Value - 1d).Saturate * MinimizedYAH * new PointBl(1, -1),
      };
      YAH.Size = (State.Value - 1d).Saturate.Lerp<PointBl>(50d, MinimizedYAH);


      YAH.OnMouseEnter = (x, y) => {
        if (CurrentState() < 1d) {
          State.Value.Animate().Duration(Dur).StopOnCompleted(true).To = 1d;
        } else if (CurrentState() > 2d) {
          State.Value.Animate().Duration(Dur).StopOnCompleted(true).To = 2d;
        }
        return true;
      };
      YAH.OnMouseDown = (x, y) => {
        if (CurrentState() >= 2d) {
          State.Value.Animate().Duration(Dur).StopOnCompleted(true).To = 1d;
        }
        return true;
      };
      var CatsLength = 5;

      EllipseBl[] CatImages = new EllipseBl[CatsLength];
      for (int i = 0; i < CatsLength; i++) {
        DoubleBl CatLength = CatsLength - 1;
        DoubleBl di = i;
        di = di / CatLength;
        var angle = (1d + 1d * di).PI();
        DoubleBl CatExpanded = State.Value;
        CatExpanded = (CatExpanded >= 1d).Condition((2d - CatExpanded).Max(0d), CatExpanded);
        var Expanded = CatExpanded.Ease.Circ.InOut;
        CatImages[i] = new EllipseBl(Self) {
          Stroke = { Thickness = 0 },
          ZIndex = (i == SelectedCat & State.Value > 1d).Condition(YAH.ZIndex + 1, YAH.ZIndex - 1), // appear under the YAH.
          CenterPosition = Self.CenterSize + CatRadius * Expanded * angle.ToPoint,
          Size = 50d,
        };
        CatImages[i].Fill = Brushes.Transparent; //  (i + 1).SelectColor() * CatImages[i].IsMouseOver.Condition(.5d.Bl(), 1d.Bl());

        var label = new LabelBl(Self) {
          ZIndex = CatImages[i].ZIndex,
          //Source = ("Resources/text_" + Cats[i] + ".PNG").ImageFor(typeof(BubbleTest)).Bl(),
          Content = "Cat" + i,
          Visibility = CatImages[i].IsMouseOver & (RoundedState == 1d),
        };
        if (i <= 1) label.RightCenter = CatImages[i].LeftCenter - new PointBl(10, 0);
        else if (i == 2) label.CenterBottom = CatImages[i].CenterTop - new PointBl(0, 10);
        else label.LeftCenter = CatImages[i].RightCenter + new PointBl(10, 0);

        CatImages[i].OnMouseEnter = (x, y) => {
          if (CurrentState() > 2d) { // go back from idle.
            State.Value.Animate().Duration(Dur).StopOnCompleted(true).To = 2d;
          }
          return true;
        };
      }
      var points = new PointBl[CatImages.Length + 1];
      var colors = new BoolBl[CatImages.Length + 1];
      points[0] = YAH.CenterPosition;
      colors[0] = YAH.IsMouseOver;
      for (int i = 1; i < CatImages.Length + 1; i++) {
        points[i] = CatImages[i - 1].CenterPosition;
        colors[i] = CatImages[i - 1].IsMouseOver;
      }

      var StateB = State.Value.Min(1d).Sqrt;

      var SizeB = new LabelSliderBl(Self) {
        LeftTop = State.LeftBottom, Width = State.Width, LabelName = "SizeB",
        Minimum = .0050, Maximum = .0300, Value = .00725, Visibility = false,
      };
      SizeB.Value = StateB.Lerp(.0300.Bl(), .00725);

      var Delta = new LabelSliderBl(Self) {
        LeftTop = SizeB.LeftBottom, Width = State.Width, LabelName = "Delta",
        Minimum = .0001, Maximum = .0050, Value = .0015,
      };


      // categories first.
      Map.Effect.Custom = (input,uv) => {
        ColorBl color = Colors.Black;
        DoubleBl metaball = 0;
        var sz = Self.Size;
        for (int i = 0; i < points.Length; i++) {
          var point = points[i];
          var v = (uv * Self.Size - point);
          v = v * v;
          var at = 3d / (v.X + v.Y);
          //at = at * colors[i].Condition(2d, 1d);
          var primary = StateB.Lerp(Colors.Black, i.SelectColor());
          //color += ((primary) * at);

          color += colors[i].Condition(1d - primary.ScRGB, primary) * at;
          metaball += at;
        }
        var useColor = color / metaball;
        //(SizeA > SizeB).Assert();

        var lerp = ((metaball - SizeB).Max(0) / (Delta)).Min(1d);
        //var lerp = (metaball / SizeB).Saturate;

        return lerp.Lerp((1d - useColor.ScRGB) * 1d, useColor);

        //return (metaball > SizeA).Condition(useColor, (metaball > SizeB).Condition((metaball / (SizeA - SizeB))   , Colors.White.Bl()));
      };
      var SubCatsLength = 8;
      EllipseBl[] SubCatImages = new EllipseBl[SubCatsLength];
      for (int i = 0; i < SubCatsLength; i++) {
        DoubleBl SubCatLength = SubCatsLength;
        DoubleBl di = i;
        di = di / SubCatLength;
        var angle = (2d * di).PI();
        DoubleBl SubCatExpanded = (State.Value - 1d).Max(0);
        SubCatExpanded = (SubCatExpanded >= 1d).Condition((2d - SubCatExpanded), SubCatExpanded);

        var Expanded = SubCatExpanded.Ease.Circ.InOut;
        SubCatImages[i] = new EllipseBl(Self) {
          ZIndex = YAH.ZIndex - 2, // appear under the YAH.
          Stroke = { Thickness = 0 },
          CenterPosition = Self.CenterSize + SubCatRadius * Expanded * angle.ToPoint,
          Size = 50d,
        };
        SubCatImages[i].Fill = Brushes.Transparent; // i.SelectColor() * SubCatImages[i].IsMouseOver.Condition(.8d.Bl(), 1d.Bl());
        /*
        SubCatImages[i].Source = SubCatImages[i].IsMouseOver.Condition(
          ("Resources/icon_mouseover_" + SubCats[i] + ".PNG").ImageFor(typeof(BubbleTest)).Bl(),
          ("Resources/icon_" + SubCats[i] + ".PNG").ImageFor(typeof(BubbleTest)).Bl()
        );*/
      }
      Action<int> SetSelectedCat = SelectedCat.MakeAssign;
      CatImages[0].OnMouseDown = (x, y) => {
        if (CurrentState() < 2d) {
          SetSelectedCat(0);
          // prepare images if necessary.
          State.Value.Animate().Duration(Dur).StopOnCompleted(true).To = 2d;
        }
        return true;
      };
      Timer.LockTime = LockTime0;
    }
    public void Start() { Timer.Start(); }
    public void Stop() { Timer.Stop(); }

  }
}